package com.yanlight.util;

import com.alibaba.fastjson.JSONObject;
import com.yanlight.app.dal.entity.WxAccessToken;
import com.yanlight.app.request.WxMessageRequest;
import com.yanlight.app.request.WxRedPacketRequest;
import com.yanlight.app.request.WxTransfersRequest;
import com.yanlight.app.response.WxRedPacketResponse;
import com.yanlight.app.response.WxTransfersResponse;
import com.yanlight.support.wx.WxConstants;
import com.yanlight.support.wx.util.SignatureUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.util.HashMap;
import java.util.SortedMap;

public class WxHttpClientUtil {

    // 连接超时时间，默认30秒
    private static int socketTimeout = 30000;

    // 传输超时时间，默认30秒
    private static int connectTimeout = 30000;


    private static final String ACCESS_TOKEN = "accessToken";

    private static final String send_message_url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";

    private static final String applyMoneyTemplateId = "HVTnN3U2F8bM9XjtA8VLgElGQQcVej-SGcWgskuSBME";

    private final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

    /**
     * xml请求
     *
     * @param postData
     * @return
     */
    @SuppressWarnings("deprecation")
    public static String xmlPost(String url, String mchId, String certPath, String postData) {
        String result = null;
        try {
            KeyStore keyStore = getKeyStore(mchId, certPath);
            HttpPost httpPost = new HttpPost(url);
            SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
            SSLConnectionSocketFactory sslcs = new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslcs).build();
            result = executePost(httpclient, httpPost, postData);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    private static String executePost(CloseableHttpClient httpclient, HttpPost httpPost, String postData) throws Exception {
        StringEntity postEntity = new StringEntity(postData, "UTF-8");
        httpPost.addHeader("Content-Type", "text/xml");
        httpPost.setConfig(getRequestConfig());
        httpPost.setEntity(postEntity);

        HttpResponse httpResponse = httpclient.execute(httpPost);
        HttpEntity httpEntity = httpResponse.getEntity();
        String result = EntityUtils.toString(httpEntity, "UTF-8");

        return result;
    }

    /**
     * 加载证书
     *
     * @return
     * @throws KeyStoreException
     * @throws FileNotFoundException
     */
    private static KeyStore getKeyStore(String mchId, String certPath)
            throws KeyStoreException, FileNotFoundException {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        FileInputStream inputStream = new FileInputStream(new File(certPath));
        try {
            keyStore.load(inputStream, mchId.toCharArray());
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return keyStore;
    }

    /**
     * HTTP默认请求参数设置
     *
     * @return
     */
    private static RequestConfig getRequestConfig() {
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
        return requestConfig;
    }

    /**
     * 获取access_token
     *
     * @param appId     凭证
     * @param appSecret 密钥
     * @return
     */
    public static WxAccessToken getAccessToken(String appId, String appSecret) {

        WxAccessToken cachedToken = JedisUtil.get(ACCESS_TOKEN, WxAccessToken.class);
        if (cachedToken == null || StringUtils.isBlank(cachedToken.getToken())) {
            String requestUrl = access_token_url.replace("APPID", appId).replace("APPSECRET", appSecret);

            HttpGet httpGet = new HttpGet(requestUrl);

            CloseableHttpClient httpclient = HttpClients.custom().build();
            try {
                HttpResponse httpResponse = httpclient.execute(httpGet);
                HttpEntity httpEntity = httpResponse.getEntity();
                String result = EntityUtils.toString(httpEntity, "UTF-8");
                JSONObject jsonObject = JSONObject.parseObject(result);
                WxAccessToken resultAccess = new WxAccessToken();
                if (jsonObject.containsKey("access_token")) {
                    resultAccess.setToken(jsonObject.getString("access_token"));
                } else {
                    return null;
                }

                if (jsonObject.containsKey("expires_in")) {
                    int expires_in = jsonObject.getInteger("expires_in");
                    if (expires_in > 100) {
                        //提前100秒设置刷新
                        expires_in -= 100;
                    }
                    resultAccess.setExpiresIn(expires_in);
                } else {
                    resultAccess.setExpiresIn(7100);
                }

                JedisUtil.expire(ACCESS_TOKEN, resultAccess, resultAccess.getExpiresIn());
                return resultAccess;

            } catch (IOException e) {
                return null;
            }
        } else {
            return cachedToken;
        }
    }

    /**
     * 发送红包
     */
    public static WxRedPacketResponse sendRedPacket(String authId, Integer amount) {
        String nonceStr = RandomStringUtil.randomAlphanumeric(32);
        String nowTimeNoChar = DateTimeUtil.getNowTimeNoChar();

        String orderNumber = WxConstants.mchId + nowTimeNoChar + RandomStringUtil.randomNumeric(4);
        WxRedPacketRequest request = new WxRedPacketRequest();
        request.setMch_billno(orderNumber);
        request.setNonce_str(nonceStr);
        request.setWxappid(WxConstants.appId);
        request.setMch_id(WxConstants.mchId);
        request.setSend_name("微食刻");
        request.setRe_openid(authId);
        request.setTotal_amount(amount);
        request.setTotal_num(1);
        request.setWishing("幸运红包！");
        request.setClient_ip("39.98.40.103");
        request.setAct_name("幸运红包");
        request.setRemark("先到先得哦");
        request.setScene_id("PRODUCT_1");

        SortedMap<String, String> stringStringSortedMap = request.setupParams();
        String apiSignHMAC = SignatureUtil.createApiSign(stringStringSortedMap, WxConstants.apiKey);
        request.setSign(apiSignHMAC);
        String xmlFromObj = XmlParseUtil.getXmlFromObj(request);

        String result = WxHttpClientUtil.xmlPost(WxConstants.WX_RED_PACKET, WxConstants.mchId, WxConstants.certPath, xmlFromObj);

        LogUtil.showLog("发送红包结果", result);
        WxRedPacketResponse redPacketResponse = XmlUtil.xmlToObject(result, WxRedPacketResponse.class);
        LogUtil.showLog("发送红包结果", redPacketResponse);

        return redPacketResponse;
    }

    /**
     * 转账
     */
    public static WxTransfersResponse transfers(String authId, Integer amount) {
        String nonceStr = RandomStringUtil.randomAlphanumeric(32);
        String nowTimeNoChar = DateTimeUtil.getNowTimeNoChar();

        String orderNumber = WxConstants.mchId + nowTimeNoChar + RandomStringUtil.randomNumeric(4);
        WxTransfersRequest request = new WxTransfersRequest();
        request.setMch_appid(WxConstants.appId);
        request.setMchid(WxConstants.mchId);
        request.setNonce_str(nonceStr);
        request.setSpbill_create_ip("39.98.40.103");
        request.setOpenid(authId);
        request.setAmount(amount);
        request.setPartner_trade_no(orderNumber);

        SortedMap<String, String> stringStringSortedMap = request.setupParams();
        String apiSignHMAC = SignatureUtil.createApiSign(stringStringSortedMap, WxConstants.apiKey);
        request.setSign(apiSignHMAC);

        String result = WxHttpClientUtil.xmlPost(WxConstants.WX_TRANSFERS, WxConstants.mchId, WxConstants.certPath, XmlParseUtil.getXmlFromObj(request));
        LogUtil.showLog("转账结果", result);
        WxTransfersResponse wxTransfersResponse = XmlUtil.xmlToObject(result, WxTransfersResponse.class);
        LogUtil.showLog("转账结果", wxTransfersResponse);
        return wxTransfersResponse;
    }

    /**
     * 发送申请贷款的消息通知
     */
    public static void applyMoneyMessage(String openId, String operateUrl) {

        WxAccessToken accessToken = getAccessToken(WxConstants.appId, WxConstants.appSecret);
        if (accessToken == null || StringUtils.isBlank(accessToken.getToken())) {
            LogUtil.showLog("消息发送失败");
        } else {
            String requestUrl = send_message_url.replace("ACCESS_TOKEN", accessToken.getToken());


            WxMessageRequest request = new WxMessageRequest();
            request.setTouser(openId);
            request.setTemplate_id(applyMoneyTemplateId);
            request.setUrl(operateUrl);

            HashMap<String, WxMessageRequest.TemplateData> data = new HashMap<>();
            WxMessageRequest.TemplateData first = new WxMessageRequest.TemplateData();
            first.setValue("聚合支付通知");
            first.setColor("#FF4500");

            WxMessageRequest.TemplateData keyword1 = new WxMessageRequest.TemplateData();
            keyword1.setValue("贷款申请");

            WxMessageRequest.TemplateData keyword2 = new WxMessageRequest.TemplateData();
            keyword2.setValue(DateTimeUtil.getNowTime());

            WxMessageRequest.TemplateData remark = new WxMessageRequest.TemplateData();
            remark.setValue("点击查看详情");

            data.put("first", first);
            data.put("keyword1", keyword1);
            data.put("keyword2", keyword2);
            data.put("remark", remark);

            request.setData(data);

            HttpPost httpPost = new HttpPost(requestUrl);
            CloseableHttpClient httpclient = HttpClients.custom().build();

            try {
                String result = executePost(httpclient, httpPost, JSONObject.toJSONString(request));

                LogUtil.showLog(result);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }
}
